from dcatalyst import Chained, ChainError
import unittest

@Chained(path_part='articles')
def first_method(req, arg1):
    req['arg1'] = arg1
    
@Chained(first_method, path_part='')
def second_method(req, arg2, arg3, arg4):
    req['arg2'] = arg2
    req['arg3'] = arg3
    req['arg4'] = arg4

@Chained(second_method, path_part='')
def third_method(req, arg5='something'):
    req['arg5'] = arg5

class TestChainingMethods(unittest.TestCase):

    def setUp(self):
        self.req = {}    

    def test_simple_call(self):
        args = ['ana', 'are', 'mere', 'si', 'pere']
        third_method(self.req, *args)
        for i in range(len(args)):
            self.assertEquals(args[i], self.req['arg'+str(i+1)])
            
    def test_default_argument_last(self):
        args = ['ana', 'are', 'mere', 'si']
        third_method(self.req, *args)
        for i in range(len(args)):
            self.assertEquals(args[i], self.req['arg'+str(i+1)])
        self.assertEquals('something', self.req['arg5'])

    def test_default_argument_first(self):
        args = ['ana', 'are', 'mere', 'si']
        kwa  = {'arg1': 'ea'}
        third_method(self.req, *args, **kwa)
        for i in range(len(args)):
            self.assertEquals(args[i], self.req['arg'+str(i+2)])
        self.assertEquals('ea', self.req['arg1'])

    def test_default_argument_first_last(self):
        args = ['ana', 'are', 'mere']
        kwa  = {'arg1': 'ea'}
        third_method(self.req, *args, **kwa)
        for i in range(len(args)):
            self.assertEquals(args[i], self.req['arg'+str(i+2)])
        self.assertEquals('ea', self.req['arg1'])
        self.assertEquals('something', self.req['arg5'])

    def test_all_defaults(self):
        kwa  = {'arg1': 'ana', 'arg2': 'are', 'arg3': 'mere', 'arg4': 'si', 'arg5': 'pere'}
        third_method(self.req, **kwa)
        for k in kwa.keys():
            self.assertEquals(kwa[k], self.req[k])

    def test_almost_all_defaults(self):
        kwa  = {'arg1': 'ana', 'arg2': 'are', 'arg3': 'mere', 'arg4': 'si'}
        third_method(self.req, 'pere', **kwa)
        for k in kwa.keys():
            self.assertEquals(kwa[k], self.req[k])
        self.assertEquals('pere', self.req['arg5'])

    def test_error_simple(self):
        # one argument missing
        args = ['ana', 'are', 'mere']
        try:
            third_method(self.req, *args)
            self.assert_(False)
        except TypeError:
            self.assert_(True)

    def test_named_argument_error(self):
        try:
            # arg3 can't be a named parameter when arg4 isn't
            third_method(self.req, 'ana', 'are', 'si', 'pere', arg3='mere')
            self.assert_(False)
        except TypeError:
            self.assert_(True)
            

    def test_error_duplicate_parameter(self):
        try:
            @Chained(third_method)
            def err_f(req, arg1):
                pass
            self.assert_(False)
        except ChainError:
            self.assert_(True)



if __name__ == '__main__':
    unittest.main()
